#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 100005
#define inf 0x7fffffff
int arr[maxn], tmp, len, o1 = -inf, o2 = -inf;
int f[maxn], g[maxn];
//根据Dilworth定理,对于任意有限偏序集，其最大反链中元素的数目必等于最小链划分中链的数目
void showF()
{
    cout << "f:";
    for (int i = 0; i <= o1; ++i)
        cout << f[i] << " ";
    cout << endl;
}
int main()
{
    while (scanf("%d", &tmp) != EOF)
    {
        arr[len++] = tmp;
    }
    o1 = 0, o2 = 0;
    f[0] = -inf, g[0] = inf; //f表示不上升的子序列,g表示上升子序列
    for (int i = 0; i < len; ++i)
    {
        // cout << "第" << i << "次判断:";
        // showF();
        if (f[o1] >= arr[i]) //如果当前的f[o1]是大于等于arr[i]的话直接把arr[i]加入f
        {
            // printf("此时的%d >= %d,所以我们将%d加入f中,现在f的长度为:%d\n", f[o1], arr[i], arr[i], o1 + 1);
            f[++o1] = arr[i];
        }
        else //不然就找到f[0..o1]中第一个小于arr[i]的数,与其交换
        {
            int *p = upper_bound(f, f + o1, arr[i], greater<int>());
            // printf("此时%d < %d,我们需要找到f中第一个小于%d的数:%d,将其与%d所交换!\n", f[o1], arr[i], arr[i], *p, f[o1]);
            *p = arr[i];
        }
        //g的情况与f对偶
        if (g[o2] < arr[i])
        {
            g[++o2] = arr[i];
        }
        else
        {
            int *p = lower_bound(g, g + o2, arr[i]);
            *p = arr[i];
        }
    }
    printf("%d\n%d", o1 + 1, o2 + 1);
    return 0;
}